package testClasses.misc;

import events.stateMachine.strategyState.DefaultViewEvent;
import galaxies.GalaxySizeCalculator;
import galaxies.GalaxySpiralBuilder2;
import galaxies.SpiralStarLocationGenerator;
import galaxies.enums.EGalaxyType;
import galaxies.sectors.SpiralSectorBuilder;
import galaxies.starRegions.StarRegionSpiralArmModel;
import galaxies.starRegions.StarRegionSpiralBuilder;
import galaxies.starRegions.StarRegionSpiralCoreModel;
import gameAppLayer.GameSettings;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode;

import testClasses.ATest;
import testClasses.TestingSystem;
import universe.UniverseBuilder;
import utilities.CoordConvert;
import utilities.CustomMesh;
import utilities.Key;
import utilities.PointRotate;
import view.EViewList;
import view.View;
import controller.AbstractController;
import controller.IController;

public class SpiralGalaxyTest extends ATest {

	private static final Logger logger = Logger.getLogger(SpiralGalaxyTest.class.getName());
	
	public SpiralGalaxyTest(TestingSystem system) {
		super(system);
		name = "SpiralGalaxyTest";
		logger.log(Level.INFO, "SpiralGalaxyTest: Created");
	}

	@Override
	public boolean execute() {
		logger.log(Level.INFO, "SpiralGalaxyTest: execute()");
		
		HashMap<Key, IController> controllerMap = new HashMap<Key, IController>();
		eventManager.addControlMapReference(controllerMap);
		
		TestGameSettingsDefaults defaults = new TestGameSettingsDefaults();
		GameSettings settings = defaults.settings;
		
		GalaxySizeCalculator galSizeCalc = new GalaxySizeCalculator();
		HashMap<String, ArrayList<ArrayList<Integer>>> galSizes = galSizeCalc.calcGalaxyDims(settings);		
		
		String galRef = settings.getGalaxyRefs().get(0);
		
		//Only set up for one galaxy right now
		//--------------------------------------------
		ArrayList<ArrayList<Integer>> dims = galSizes.get(galRef);
		ArrayList<ArrayList<Integer>> offset = new ArrayList<ArrayList<Integer>>();
		offset.add(new ArrayList<Integer>());
		offset.get(0).add(0);
		offset.get(0).add(0);
		offset.get(0).add(0);
		
		
		logger.log(Level.INFO, "GalFact CREATING GALAXY");	
		GalaxySpiralBuilder2 galFact = new GalaxySpiralBuilder2();
		ArrayList<IController> controllers = galFact.createGalaxy(settings, eventManager, assetManager, galRef, dims);
		logger.log(Level.INFO, "GalFact DONE");
		
		int numArms = galFact.getNumArms();
		numArms = 4;
		logger.log(Level.INFO, "NumArms= " + numArms);		
		
		HashMap<Integer, ArrayList<Integer>> locations = galFact.getLocations();
		
		System.out.println("Locations Size: " + locations.size());
		eventManager.addAllListeners(controllers.get(0), controllers.get(0).getEvents().keySet());
		controllerMap.put(controllers.get(0).getKey(), controllers.get(0));		
		logger.log(Level.INFO, "Galaxy added to eventManager!");
		
//		ArrayList<Double> loc;
//		float x;
//		float y;
//		CustomMesh mesh1 = new CustomMesh(locations.size());
//		mesh1.setMode(Mode.Points);
//		mesh1.setColor(ColorRGBA.Green);
//		mesh1.setPointSize(5);		
//		
//		for (ArrayList<Integer> location : locations) {
//			
//			loc = CoordConvert.hex2Cart(location);
//			x = loc.get(0).floatValue();
//			y = loc.get(1).floatValue();
//			
//			mesh1.addVertex(x, y, 0);			
//		}
//		mesh1.finish();
//		mesh1.setStatic();
//		
//		Geometry geo1 = new Geometry("points", mesh1);
//		Material mat1 = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
//		mat1.setBoolean("VertexColor", true);
//		//mat.setColor("Color", ColorRGBA.Green);
//		geo1.setMaterial(mat1);
//		node.attachChild(geo1);
		//--------------------------------------------
		
		
		//--------------------------------------------
		StarRegionSpiralBuilder starRegionFact = new StarRegionSpiralBuilder();
		logger.log(Level.INFO, "BUILDING CORE REGIONS");
		ArrayList<StarRegionSpiralCoreModel> coreRegions = starRegionFact.buildCoreRegions(numArms, dims.get(0));
		logger.log(Level.INFO, "CORE REGIONS DONE");
		logger.log(Level.INFO, "BUILDING ARM REGIONS");
		ArrayList<StarRegionSpiralArmModel> armRegions = starRegionFact.buildArmRegions(numArms, dims.get(0));
		logger.log(Level.INFO, "ARM REGIONS DONE");
		double coreWidth = starRegionFact.coreWidth;
		double coreSide = starRegionFact.coreSide;
		double triangleSide = starRegionFact.triangleSide;
		
//		System.out.println("CoreWidth= " + coreWidth);
//		System.out.println("CoreSide= " + coreSide);
//		System.out.println("TriangleSide= " + triangleSide);
		
		//Rotate regions
		//Rotate arm regions
		logger.log(Level.INFO, "ROTATION");
		for (StarRegionSpiralArmModel armRegion: armRegions) {
			ArrayList<Vector2f> bounds = armRegion.getBounds();
			for (Vector2f bound: bounds) {
				PointRotate.spiralRotate(triangleSide, dims.get(0).get(0), bound);
			}
		}
		
		
		ArrayList<ColorRGBA> colorList = new ArrayList<ColorRGBA>();
		colorList.add(ColorRGBA.Blue);
		colorList.add(ColorRGBA.Brown);
		colorList.add(ColorRGBA.Cyan);
		colorList.add(ColorRGBA.Magenta);
		colorList.add(ColorRGBA.Orange);
		colorList.add(ColorRGBA.Pink);
		colorList.add(ColorRGBA.Red);
		colorList.add(ColorRGBA.White);
		colorList.add(ColorRGBA.Yellow);
		colorList.add(ColorRGBA.Gray);
		
		
		//Display star region boundaries
		//----------------------------------------------------
//		Integer i = 0;
//		int j = 0;
//		for (StarRegionSpiralCoreModel coreRegion: coreRegions) {
//			ArrayList<Vector2f> boundary = coreRegion.getPoints();
//			
//			CustomMesh mesh = new CustomMesh(3);
//			mesh.setMode(Mode.Points);
//			
//			if (j > colorList.size()-1) {
//				j = 0;
//			}
//			mesh.setColor(colorList.get(j));
//			
//			for (Vector2f point: boundary) {
//				mesh.addVertex(point.x, point.y, 0.2f);			
//			}
//			
//			mesh.setPointSize(10);
//			mesh.finish();
//			mesh.setStatic();
//			
//			Geometry geo = new Geometry(i.toString(), mesh);
//			Material mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
//			mat.setBoolean("VertexColor", true);
//			//mat.setColor("Color", ColorRGBA.Green);
//			geo.setMaterial(mat);
//			node.attachChild(geo);
//			i++;
//			j++;
//		}
//		
//		j=0;
//		for (StarRegionSpiralArmModel armRegion: armRegions) {
//			ArrayList<Vector2f> boundary = armRegion.getBounds();
//			
//			CustomMesh mesh = new CustomMesh(20);
//			mesh.setMode(Mode.Points);
//			
//			if (j > colorList.size()-1) {
//				j = 0;
//			}
//			mesh.setColor(colorList.get(j));
//			
//			for (Vector2f point: boundary) {
//				mesh.addVertex(point.x, point.y, 0.2f);			
//			}
//			
//			mesh.setPointSize(10);
//			mesh.finish();
//			mesh.setStatic();
//			
//			Geometry geo = new Geometry(i.toString(), mesh);
//			Material mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
//			mat.setBoolean("VertexColor", true);
//			//mat.setColor("Color", ColorRGBA.Green);
//			geo.setMaterial(mat);
//			node.attachChild(geo);
//			i++;
//			j++;
//		}
		//----------------------------------------------------
		
		
		
//		System.out.println("REGION PRINTOUT");
//		
//		for (StarRegionSpiralArmModel armRegion: armRegions) {
//			
//			ArrayList<Vector2f> bounds = armRegion.getBounds();			
//			for (Vector2f bound: bounds) {
//				System.out.println("(X,Y)= " + bound.x + " " + bound.y);
//			}
//			
//			System.out.println("Location= " + armRegion.getLocation().x + " " + armRegion.getLocation().y);
//			
//			System.out.println("Long, Short= " + armRegion.getLongDim() + " " + armRegion.getShortDim());
//			System.out.println("StopDim= " + armRegion.getStopLongDim());
//			System.out.println("Rotation= " + armRegion.getRotation());
//			System.out.println("");
//			
//		}
		
//		System.out.println(locations.size());
//		
		//Create Sectors
		SpiralSectorBuilder sectorFact = new SpiralSectorBuilder(locations, offset.get(0));
		controllers.addAll(sectorFact.buildCoreSectors(coreRegions, triangleSide, assetManager, eventManager));
		controllers.addAll(sectorFact.buildArmSectors(armRegions, assetManager, eventManager));
		ArrayList<ArrayList<Integer>> mainBodyLocations = sectorFact.mainTileList; 
		ArrayList<ArrayList<Integer>> haloLocations = sectorFact.haloTileList;

		
		ArrayList<Double> loc;
		float x;
		float y;		
		//Display sectors
		//----------------------------------------------------

		CustomMesh mesh1 = new CustomMesh(mainBodyLocations.size());
		CustomMesh mesh2 = new CustomMesh(haloLocations.size());
		mesh1.setMode(Mode.Points);
		mesh2.setMode(Mode.Points);
		mesh1.setColor(ColorRGBA.Green);
		mesh2.setColor(ColorRGBA.Red);
		mesh1.setPointSize(5);		
		mesh2.setPointSize(5);
		
		for (ArrayList<Integer> location : mainBodyLocations) {
			
			loc = CoordConvert.hex2Cart(location);
			x = loc.get(0).floatValue();
			y = loc.get(1).floatValue();
			
			mesh1.addVertex(x, y, 0.1f);			
		}
		
		for (ArrayList<Integer> location: haloLocations) {
			loc = CoordConvert.hex2Cart(location);
			x = loc.get(0).floatValue();
			y = loc.get(1).floatValue();
			
			mesh2.addVertex(x, y, 0);			
		}
				
		mesh1.finish();
		mesh2.finish();
		mesh1.setStatic();
		mesh2.setStatic();
		
		Geometry geo1 = new Geometry("points1", mesh1);
		Geometry geo2 = new Geometry("points2", mesh2);
		Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
		Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
		mat1.setBoolean("VertexColor", true);
		mat2.setBoolean("VertexColor", true);
		//mat.setColor("Color", ColorRGBA.Green);
		geo1.setMaterial(mat1);
		geo2.setMaterial(mat2);
		node.attachChild(geo1);
		node.attachChild(geo2);
		//----------------------------------------------------
		
		//NEXT:  Select stars (disable coloring of background above to see stars clearly.  Keep in sector boundaries though).
		
		
		//Choose star locations
		int size = settings.getGalSizes(galRef);
		int density = settings.getGalaxyDensity(galRef);
		EGalaxyType type = settings.getGalaxyType(galRef);
		SpiralStarLocationGenerator starLocationFact = new SpiralStarLocationGenerator();
		ArrayList<ArrayList<Integer>> tertiaryLocations = new ArrayList<ArrayList<Integer>>();
		
		ArrayList<ArrayList<Integer>> starLocations = starLocationFact.chooseRandomLocations(
					mainBodyLocations, haloLocations, tertiaryLocations, 
					0.9, 0.1, 0.0, density, type);
		
		
		//Display star locations
		//----------------------------------------------------
		ArrayList<Double> loc1;
//		float x;
//		float y;
		CustomMesh mesh3 = new CustomMesh(starLocations.size());
		//CustomMesh mesh4 = new CustomMesh(haloLocations.size());
		mesh3.setMode(Mode.Points);
		//mesh4.setMode(Mode.Points);
		mesh3.setColor(ColorRGBA.Blue);
		//mesh4.setColor(ColorRGBA.Orange);
		mesh3.setPointSize(5);		
		//mesh4.setPointSize(5);
		
		for (ArrayList<Integer> location : starLocations) {
			
			loc1 = CoordConvert.hex2Cart(location);
			x = loc1.get(0).floatValue();
			y = loc1.get(1).floatValue();
			
			mesh3.addVertex(x, y, 0.2f);			
		}
		
//		for (ArrayList<Integer> location: haloLocations) {
//			loc1 = CoordConvert.hex2Cart(location);
//			x = loc1.get(0).floatValue();
//			y = loc1.get(1).floatValue();
//			
//			mesh4.addVertex(x, y, 0.5f);			
//		}
				
		mesh3.finish();
//		mesh4.finish();
		mesh3.setStatic();
//		mesh4.setStatic();
//		
		Geometry geo3 = new Geometry("points1", mesh3);
//		Geometry geo4 = new Geometry("points2", mesh4);
		Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
//		Material mat4 = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
		mat3.setBoolean("VertexColor", true);
//		mat4.setBoolean("VertexColor", true);
		//mat.setColor("Color", ColorRGBA.Green);
		geo3.setMaterial(mat3);
//		geo4.setMaterial(mat4);
		node.attachChild(geo3);
//		node.attachChild(geo4);
		//----------------------------------------------------
		
		
		
		//events.queueEvent(new DefaultViewEvent(node));
		//events.procEvents(1000);
		
		
		
		return true;
	}
}
